<?php

namespace RX\Helpers;

class PasswordHelper
{
    public static function generatePassword($originPassword)
    {
        return password_hash($originPassword, PASSWORD_BCRYPT, [
            'cost' => 12,
        ]);
    }

    public static function verifyPassword($originPassword, $hashedPassword)
    {
        return password_verify($originPassword, $hashedPassword);
    }

    /**
     * 二次md5加密+salt
     * @param string $str 需要加密的字符串
     * @param string $salt 盐
     * @return string
     */
    public static function doubleMd5Encrypt(string $str, string $salt = "")
    {
        $salt = empty($salt) ?? time();
        return md5(md5(trim($str) . $salt));
    }


    /**
     * hash256
     * @param string $data 需要hash的数据
     * @return string
     */
    public static function hash256(string $data)
    {
        return hash("sha256", $data);
    }


    /**
     * 加密方法，对数据进行加密
     * @param string $data 加密数据
     * @param string $secretKey 密钥
     * @param string $iv iv向量
     * @param string $method 方法
     * @return false|string
     */
    public static function encrypt(string $data, string $secretKey, string $iv, string $method = "AES-256-CBC")
    {
        return base64_encode(openssl_encrypt($data, $method, $secretKey, true, $iv));
    }


    /**
     * 需要解密的字符串
     * @param string $str 秘文
     * @param string $secretKey 密钥
     * @param string $iv iv向量
     * @param string $method 方法
     * @return false|string
     */
    public static function decrypt(string $str, string $secretKey, string $iv, string $method = "AES-256-CBC")
    {
        return openssl_decrypt(base64_decode($str), $method, $secretKey, true, $iv);
    }


    /**
     * hashHmac
     * @param string $algo 它是必需的参数，用于指定所选的哈希算法Ex。 “md5”，“sha256”，“sha1”。
     * @param string $data 此参数用于保存要散列的消息。
     * @param string $key 此参数用于指定用于生成消息摘要的HMAC变体的共享 key 。
     * @param bool $rawOpt 此参数用于保存布尔值。如果将其设置为True，则返回原始二进制数据，如果将其设置为False，则返回输出小写十六进制。
     * @return string
     */
    public static function hashHmac(string $algo, $data, $key, $rawOpt = false)
    {
        return hash_hmac($algo, $data, $key, $rawOpt);
    }

    /**
     * base32 encode
     * @param string $input
     * @return string
     */
    public static function base32Encode(string $input)
    {
        $BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
        $output          = '';
        $v               = 0;
        $vBits           = 0;

        for ($i = 0, $j = strlen($input); $i < $j; $i++) {
            $v     <<= 8;
            $v     += ord($input[$i]);
            $vBits += 8;

            while ($vBits >= 5) {
                $vBits  -= 5;
                $output .= $BASE32_ALPHABET[$v >> $vBits];
                $v      &= ((1 << $vBits) - 1);
            }
        }

        if ($vBits > 0) {
            $v      <<= (5 - $vBits);
            $output .= $BASE32_ALPHABET[$v];
        }

        return $output;
    }

    /**
     * base32 decode
     * @param string $input
     * @return string
     */
    public static function base32Decode(string $input)
    {
        $output = '';
        $v      = 0;
        $vBits  = 0;

        for ($i = 0, $j = strlen($input); $i < $j; $i++) {
            $v <<= 5;
            if ($input[$i] >= 'a' && $input[$i] <= 'z') {
                $v += (ord($input[$i]) - 97);
            } elseif ($input[$i] >= '2' && $input[$i] <= '7') {
                $v += (24 + $input[$i]);
            } else {
                return "";
            }

            $vBits += 5;
            while ($vBits >= 8) {
                $vBits  -= 8;
                $output .= chr($v >> $vBits);
                $v      &= ((1 << $vBits) - 1);
            }
        }
        return $output;
    }


    /**
     * @desc base62编码
     * @param string $data
     * @return string
     **/
    public static function base62Encode(string $data)
    {
        $base62str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $data      = strval($data);
        $base62    = str_split($base62str);
        $len       = strlen($data);
        $i         = 0;
        $tmpArr    = array();
        while ($i < $len) {
            $tmp    = str_pad(decbin(ord($data[$i])), 8, '0', STR_PAD_LEFT);
            $temp   = str_split($tmp, 4);
            $tmpArr = array_merge($tmpArr, $temp);
            ++$i;
        }
        $result = '';
        $i      = 0;
        foreach ($tmpArr as $arr) {
            $temp   = bindec($arr) * 4 + $i % 2;
            $result .= $base62[$temp];
            ++$i;
        }
        return $result;
    }


    /**
     * @desc base62解码
     * @param string $data
     * @return string
     **/
    public static function base62Decode(string $data)
    {
        $base62str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $data      = strval($data);
        $base62    = str_split($base62str);
        $base62Arr = array_flip($base62);
        if (!preg_match('/[a-zA-Z0-9]+/', $data)) {
            return false;
        }

        $len     = strlen($data);
        $i       = 0;
        $tempArr = array();
        while ($i < $len) {
            $temp      = decbin(($base62Arr[$data[$i]] - $i % 2) / 4);
            $tempArr[] = str_pad($temp, 4, '0', STR_PAD_LEFT);
            ++$i;
        }
        $result  = '';
        $tempArr = array_chunk($tempArr, 2);
        foreach ($tempArr as $arr) {
            $result .= chr(bindec(join('', $arr)));
        }
        return $result;
    }


    public static function code62ShortUrl(string $url)
    {
        $url  = crc32($url);
        $x    = sprintf("%u", $url);
        $show = '';
        while ($x > 0) {
            $s = $x % 62;
            if ($s > 35) {
                $s = chr($s + 61);
            } elseif ($s > 9 && $s <= 35) {
                $s = chr($s + 55);
            }
            $show .= $s;
            $x    = floor($x / 62);
        }
        return $show;
    }
}
